import parserbasic
import plannersupport
import math

class GoalTest(object):
    def __init__(self, tests):
        self.tests = tests
        
    def __call__(self, state, env):
        for t in self.tests:
            if not eval(t, env, state):
                return False
        return True

    def results(self,state,env):
        res = []
        for t in self.tests:
            res.append((eval(t, env, state) != 0))
        return res

    def distance(self,state,env,exp=2.0):
        d = 0
        def lessPenalty(x,y):
            if isinstance(x,int) and isinstance(y,int):
                return max(1+x-y,0)
            else:
                return max(x-y,0)
        
        def greaterPenalty(x,y):
            if isinstance(x,int) and isinstance(y,int):
                return max(1+y-x,0)
            else:
                return max(y-x,0)
        
        comparisons = [('==',lambda x,y:abs(x-y)),
                   ('>=',lambda x,y:max(y-x,0)),
                   ('<=',lambda x,y:max(x-y,0)),
                   ('<',lessPenalty),
                   ('>',greaterPenalty)]
        for t in self.tests:
            comp = [c for c in comparisons if t.find(c[0])>=0]
            if len(comp)>=1:
                (c,pen) = comp[0]
                lhs,rhs = t.split(c)
                lhs = eval(lhs, env, state)
                rhs = eval(rhs, env, state)
                for (a,b) in zip(plannersupport.flatten(lhs),plannersupport.flatten(rhs)):
                    try:
                        penalty = pen(a,b)
                        d += math.pow(penalty,exp)
                    except: 
                        pass
            elif not eval(t, env, state):
                d += 1.0
        return math.pow(d,1.0/exp)

class GoalParser(object):
    def __init__(self, env):
        pass
        
    def parse(self, code, start):
        tests = []
        for line in code:
	    line = line.strip()
            #check for empty line
	    if len(line)==0: continue
            tests.append(line)
        return GoalTest(tests)
